/* io_usb.c
**
** Copyright 2006, Brian Swetland.  All rights reserved.
** See provided LICENSE file or http://frotz.net/LICENSE for details.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

#include "protocol.h"
#include "debugger.h"
#include "usb.h"

static void
io_common(unsigned addr, unsigned count, unsigned cmd)
{
    usb_msg msg;
    if(count > 4096) {
        IOERROR("transfers > 4096 not supported");
        return;
    }
    msg.cmd = cmd;
    msg.tag = '@';
    msg.len = count;
    msg.addr = addr;
    if(usb_write(&msg, sizeof(msg)) != sizeof(msg)) {
        IOERROR("failed to write msg header");
        return;
    }
}

static void
read_common(unsigned addr, void *ptr, unsigned count, unsigned cmd)
{
    io_common(addr, count, cmd);
    if(usb_read(ptr, count) != count) {
        IOERROR("failed to read payload");
    }
}

static void
write_common(unsigned addr, void *ptr, unsigned count, unsigned cmd)
{
    io_common(addr, count, cmd);
    if(usb_write(ptr, count) != count){
        IOERROR("failed to write payload");
    }
}

static void
usb_rd32x(DebugIO *io, unsigned a, unsigned *p, unsigned c)
{
    read_common(a, p, c, MSG_RD_WORDS);
}

static void
usb_wr32x(DebugIO *io, unsigned a, unsigned *p, unsigned c)
{
    write_common(a, p, c, MSG_WR_WORDS);
}

static void
usb_jump_to(DebugIO *io, unsigned addr) 
{
    io_common(addr, 0, MSG_JUMP);
}

static unsigned
usb_rd32(DebugIO *io, unsigned addr)
{
    unsigned x;
    usb_rd32x(io, addr, &x, 4);
    return x;
}

static void
usb_wr32(DebugIO *io, unsigned addr, unsigned value)
{
    usb_wr32x(io, addr, &value, 4);
}

static void
usb_halt(DebugIO *io)
{
    io_common(0, 0, MSG_STOP);
}

#if 0
static void
_read_bytes(unsigned a, void *p, unsigned c)
{
    read_common(a, p, c, MSG_RD_BYTES);
}

static void
_write_bytes(unsigned a, void *p, unsigned c)
{
    write_common(a, p, c, MSG_WR_BYTES);
}

static unsigned
_read8(unsigned addr)
{
    unsigned char x;
    _read_bytes(addr, &x, 1);
    return x;
}

static void
_write8(unsigned addr, unsigned value)
{
    _write_bytes(addr, &value, 1);
}

static void
_resume()
{
    io_common(0, 0, MSG_RESUME);
}

static void
_read_regs(unsigned *r)
{
    read_common(0, r, 17*4, MSG_RD_REGS);
}
#endif

static void
usb_connect(DebugIO *io)
{
    if(io->online) return;

    if(usb_open(0x4242, 0x0001, 0, 0x81, 0x03)) {
        return;
    }

    io->online = 1;
}

static void
usb_disconnect(DebugIO *io)
{
    if(io->online) {
        usb_close();
        io->online = 0;
    }   
}

DebugIO DebugIO_USB =
{
    ._rd32 = usb_rd32,
    ._wr32 = usb_wr32,
    ._rd32x = usb_rd32x,
    ._wr32x = usb_wr32x,
    ._jump_to = usb_jump_to,
    ._halt = usb_halt,
    .connect = usb_connect,
    .disconnect = usb_disconnect,

    .name = "USB",
};
